package net.sk.china.common.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import net.sk.china.common.exception.TalkException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.SecureRandom;
import java.text.NumberFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 通用配置类
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/4 16:24
 * // +----------------------------------------------------------------------
 */

public class TalkUtil {

    private final static SecureRandom RANDOM = new SecureRandom();

    /**
     * 字符串分割，转化为数组
     * @param str 字符串
     * @return {@code List<Integer>}
     */
    public static List<Integer> stringToArray(String str){
        return stringToArrayByRegex(str, ",");
    }

    /**
     * json字符串转集合
     * @param str 字符串
     * @return List<T>
     */
    public static <T> List<T> jsonToListClass(String str, Class<T> cls){
        try{
            return JSONObject.parseArray(str, cls);
        }catch (Exception e){
            return new ArrayList<>();
        }
    }

    /**
     * 字符串分割，转化为集合
     * @param str 字符串
     * @return {@code List<String>}
     */
    public static List<String> stringToArrayStr(String str){
        if (StrUtil.isBlank(str)) { return new ArrayList<>(); }
        return stringToArrayStrRegex(str, ",");
    }

    /**
     * 字符串分割，转化为数组
     * @param str 字符串
     * @param regex 分隔符
     * @return {@code List<Integer>}
     */
    public static List<Integer> stringToArrayByRegex(String str, String regex){
        List<Integer> list = new ArrayList<>();
        if (str.contains(regex)){

            String[] split = str.split(regex);


            for (String value : split) {
                if(!StringUtils.isBlank(value)){
                    list.add(Integer.parseInt(value.trim()));
                }
            }
        }else {
            list.add(Integer.parseInt(str));
        }
        return list;
    }

    /**
     * 字符串分割，转化为整形集合
     * @param str 待转换的数字字符串
     * @return {@code List<Integer>}
     */
    public static List<Integer> stringToArrayInt(String str){
        List<String> strings = stringToArrayStrRegex(str, ",");
        List<Integer> ids = new ArrayList<>();
        for (String string : strings) {
            ids.add(Integer.parseInt(string.trim()));
        }

        return ids;
    }

    /**
     * 字符串分割，转化为集合
     * @param str 字符串
     * @param regex 分隔符
     * @return {@code List<String>}
     */
    public static List<String> stringToArrayStrRegex(String str, String regex){
        List<String> list = new ArrayList<>();
        if (str.contains(regex)){

            String[] split = str.split(regex);

            for (String value : split) {
                if(!StringUtils.isBlank(value)){
                    list.add(value);
                }
            }
        }else {
            list.add(str);
        }
        return list;
    }

    /**
     * 获取客户端ip
     * @param request 参数
     * @return {@code String}
     */
    public static String getClientIp(HttpServletRequest request){
        // 反向代理
        String ip = request.getHeader("X-Forwarded-For");
//        if(checkIsIp(ip)){
//            return ip;
//        }
//
//        ip = request.getHeader("X-Real-IP");
//        if(checkIsIp(ip)){
//            return ip;
//        }
//
//        //本地 localhost访问 ipv6
//        ip = request.getRemoteAddr();
//        String ipv6 = "0:0:0:0:0:0:0:1";
//        if(ip.equals(ipv6)){
//            ip = "127.0.0.1";
//        }
//        if(checkIsIp(ip)){ return ip; }
//
//        return "";
        String unKnown = "unKnown";
        // 代理
        if (ip == null || ip.length() == 0 || unKnown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        // WebLogic服务器代理
        if (ip == null || ip.length() == 0 || unKnown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        // Apache服务器代理
        if (ip == null || ip.length() == 0 || unKnown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        // 多重代理或负载均衡器
        if (ip == null || ip.length() == 0 || unKnown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || unKnown.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        //本地 localhost访问 ipv6
        String ipv6 = "0:0:0:0:0:0:0:1";
        if(ip.equals(ipv6)){
            ip = "127.0.0.1";
        }
        return ip;
    }

    /**
     * 检测是否为ip
     * @param ip 参数
     * @return {@code String}
     */
    private static boolean checkIsIp(String ip){
        if(StringUtils.isBlank(ip)){ return false; }

        String unKnown = "unKnown";
        if(ip.equals(unKnown)){ return false; }

        return ip.split("\\.").length == 4;
    }

    /**
     * 加密
     * @param pwd 密码
     * @param key 加密的key
     * @return {@code String}
     */
    public static String encryptPassword(String pwd, String key) {
        try {
            Key secretKey = getDesSecretKey(key);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] data = pwd.getBytes(StandardCharsets.UTF_8);
            byte[] result = cipher.doFinal(data);

            return Base64.getEncoder().encodeToString(result);
        } catch (Exception e){
            throw new TalkException("密码处理异常：" + e.getMessage());
        }
    }

    /**
     * 解密
     * @param pwd 密码
     * @param key 解密的key
     * @return {@code String}
     */
    public static String decryptPassword(String pwd, String key) {
        try {
            Key aKey = getDesSecretKey(key);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, aKey);

            byte[] data = new sun.misc.BASE64Decoder().decodeBuffer(pwd);
            byte[] result = cipher.doFinal(data);

            return new String(result, StandardCharsets.UTF_8);
        } catch (Exception e){
            throw new TalkException("密码处理异常：" + e.getMessage());
        }
    }

    /**
     * 获得DES加密秘钥
     * @param key 加密key
     * @return {@code SecretKey}
     */
    private static SecretKey getDesSecretKey(String key) throws UnsupportedEncodingException {
        byte[] result = new byte[8];
        byte[] keys = null;
        keys = key.getBytes(StandardCharsets.UTF_8);
        for(int i = 0; i < 8; i++){
            if(i < keys.length){
                result[i] = keys[i];
            }else{
                result[i] = 0x01;
            }
        }
        return new SecretKeySpec(result, "DES");
    }

    /**
     * 随机生成密码 使用des方式加密
     * @param phone 手机号
     * @return {@code String}
     */
    public static String createPwd(String phone) {
        String password = "Cloud" + randomCount(10000, 99999);
        return encryptPassword(password, phone);
    }

    /**
     * 根据长度生成随机数字
     * @param start 起始数字
     * @param end 结束数字
     * @return {@code int}
     */
    public static int randomCount(Integer start, Integer end){
        return RANDOM.nextInt(start) + (end - start) + 1;
    }


    /**
     * 生成指定范围内的随机数
     * @param size 总数
     * @return {@code int}
     */
    private static int randomCount(Integer size){ return RANDOM.nextInt(size); }

    /**
     * map转对象
     * @param map Object
     * @param clz 对象
     * @return {@code T}
     */
    public static <T> T mapToObj(Object map, Class<T> clz){
        if (map == null) { return null; }
        return JSONObject.parseObject(JSONObject.toJSONString(map), clz);
    }

    /**
     * 图片路径转base64
     * @param path 图片路径
     * @return {@code String}
     */
    public static String getPathToBase64Image(String path) {
        try {
            File file = new File(path);
            byte[] content = new byte[(int) file.length()];
            FileInputStream stream = new FileInputStream(file);
            stream.read(content);
            stream.close();
            return Base64.getEncoder().encodeToString(content);
        } catch (IOException e) {
            e.printStackTrace();
            throw new TalkException("图片路径转换错误：" + e.getMessage());
        }
    }

    /**
     * 图片URL转base64
     * @param imageUrl 图片url
     * @return {@code String}
     */
    public static String imageUrlToBase64(String imageUrl) {
        try {
            URL url = new URL(imageUrl);
            InputStream in = url.openStream();
            byte[] bytes = IOUtils.toByteArray(in);
            return Base64.getEncoder().encodeToString(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            throw new TalkException("图片URL转换错误：" + e.getMessage());
        }
    }

    /**
     * 获取uuid
     * @return String
     */
    public static String getUuid(){
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 脱敏处理
     * @param string 脱敏的字符串
     * @param asterisk 星号
     * @param begin 开始
     * @param end 结束
     * @return {@code String}
     */
    public static String desensitization(String string, String asterisk, int begin, int end) {
        if (string.length() <= begin || string.length() <= end) { return string; }
        return String.format("%s%s%s", string.substring(0, begin), asterisk, string.substring(string.length() - end));
    }

    /**
     * hash 转换
     * @param base64 String 图片流
     * @return {@code String}
     */
    public static String getBase64Image(String base64) {
        return "data:image/png;base64," + base64;
    }

    /**
     * 格式化对象以生成字符串
     * @param num 对象
     * @return {@code String}
     */
    public static String numberFormat(Object num) { return NumberFormat.getInstance().format(num); }

    /**
     * 匹配新旧密码
     * @param raw 旧密码
     * @param encoded 新密码
     * @return {@code boolean}
     */
    public static boolean matches(String raw, String encoded) {
        return new BCryptPasswordEncoder().matches(raw, encoded);
    }

    /**
     * 设置密码
     * @param raw 密码
     * @return {@code String}
     */
    public static String encode(String raw) {
        return new BCryptPasswordEncoder().encode(raw);
    }

    /**
     * 随机获取数据
     * @param list 数据集合
     * @param count 条数
     * @param <T> 数据类型
     * @return {@code <T> List<T>}
     */
    public static <T> List<T> getRandomInfoList(List<T> list, int count)
    {
        List<T> newList = new ArrayList<>();
        if (list.size() <= count) { return list; }

        for (int i = 0; i < count; i++) {
            int random = randomCount(list.size() - 1);
            newList.add(list.get(random));
        }

        return newList;
    }

    /**
     * 随机获取数据，并去重
     * @param list 数据集合
     * @param count 条数
     * @param <T> 泛型数据
     * @return {@code <T> List<T>}
     */
    public static <T> List<T> getRandomUniqueList(List<T> list, int count)
    {
        if (list.size() <= count) { return list; }

        Collections.shuffle(list);

        return list.subList(0, count);
    }

    /**
     * 过滤url地址
     * @param url 地址
     * @return {@code String}
     */
    public static String getUri(String url){
        List<String> list = stringToArrayStrRegex(url, "/");
        //去掉url中的数字参数
        list.removeIf(StringUtils::isNumeric);
        // 去掉url中的逗号分隔参数
        list.removeIf(c -> c.contains(","));

        return StringUtils.join(list, "/");
    }

    /**
     * 获取fin_in_set拼装sql
     * @param field String 字段
     * @param idStr String 多个值，逗号分割
     * @return {@code String}
     */
    public static String getFindInSetSql(String field, String idStr ){
        List<Integer> list = stringToArray(idStr);
        ArrayList<String> sqlList = new ArrayList<>();
        for (Integer value: list) {
            sqlList.add(getFindInSetSql(field, value));
        }
        return "( " + StringUtils.join(sqlList, " or ") + ")";
    }

    /**
     * 获取fin_in_set拼装sql
     * @param field 字段
     * @param value 多个值，逗号分割
     * @return {@code String}
     */
    public static String getFindInSetSql(String field, Integer value ){
        return "find_in_set(" + value +", " + field + ")";
    }

    /**
     * 手机号脱敏处理
     * @param phone 手机号
     */
    public static String maskMobile(String phone) {
        if (StrUtil.isBlank(phone)) {
            return "";
        }
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }

    /**
     * 订单号生成
     * @param payType String 支付类型
     * @return 生成的随机码
     */
    public static String getOrderNo(String payType){
        return payType + randomCount(11111, 99999) + System.currentTimeMillis() + randomCount(11111, 99999);
    }

    /**
     * 通过id获取分类名称
     * @param list 分类集合
     * @param categoryIdStr id字符串
     * @return {@code String}
     */
    public static String getValueByIndex(HashMap<Integer, String> list, String categoryIdStr){
        if(list.size() < 1 || StringUtils.isBlank(categoryIdStr)){
            return "";
        }
        ArrayList<String> name = new ArrayList<>();
        List<Integer> idList = stringToArray(categoryIdStr);

        String str = "";
        for (Integer id : idList) {
            str = getStrValueByIndex(list, id);
            if(!StringUtils.isBlank(str)){
                name.add(getStrValueByIndex(list, id));
            }
        }
        if(name.size() < 1){
            return "";
        }
        return StringUtils.join(name, ",");
    }
    /**
     * 通过id获取分类名称
     * @param list 分类集合
     * @param key id
     * @return {@code String}
     */
    public static String getStrValueByIndex(HashMap<Integer, String> list, Integer key){
        if(list.size() < 1){
            return "";
        }
        return list.getOrDefault(key, "");
    }

    /**
     * unicode编码转换为汉字
     * @param unicodeStr 待转化的编码
     * @return 返回转化后的汉子
     */
    public static String UnicodeToCN(String unicodeStr) {
        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
        Matcher matcher = pattern.matcher(unicodeStr);
        char ch;
        while (matcher.find()) {
            //group
            String group = matcher.group(2);
            //ch:'李四'
            ch = (char) Integer.parseInt(group, 16);
            //group1
            String group1 = matcher.group(1);
            unicodeStr = unicodeStr.replace(group1, ch + "");
        }

        return unicodeStr.replace("\\", "").trim();
    }
}
